package us.sunrisemorning.douyuchat;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;

import org.tio.client.intf.ClientAioHandler;
import org.tio.core.ChannelContext;
import org.tio.core.GroupContext;
import org.tio.core.exception.AioDecodeException;
import org.tio.core.intf.Packet;

import com.google.common.eventbus.EventBus;

public class MessageClientAioHandler implements ClientAioHandler {
	private EventBus eventBus = new EventBus();
	
	public MessageClientAioHandler(MessageListener messageListener) {
		eventBus.register(messageListener);
	}

	@Override
	public Packet decode(ByteBuffer buffer, int limit, int position, int readableLength, ChannelContext channelContext)
			throws AioDecodeException {
		if (readableLength < MessagePacket.LENGTH_LENGTH) {
			return null;
		}

		buffer.order(ByteOrder.LITTLE_ENDIAN);
		int bodyLength = buffer.getInt();

		if (bodyLength < 0) {
			throw new AioDecodeException(
					"bodyLength [" + bodyLength + "] is not right, remote:" + channelContext.getClientNode());
		}

		int isDataEnough = readableLength - bodyLength - MessagePacket.LENGTH_LENGTH;
		if (isDataEnough < 0) {
			return null;
		} else {
			MessagePacket p = new MessagePacket();
			if (bodyLength > MessagePacket.HEADER_LENGTH) {
				p.setLength(bodyLength);
				int length = buffer.getInt();
				if (bodyLength != length) {
					throw new AioDecodeException("bodyLength [" + bodyLength + "] is not equal [" + length
							+ "], remote:" + channelContext.getClientNode());
				}
				p.setType(buffer.getShort());
				p.setEncryptType(buffer.get());
				p.setReserved(buffer.get());
				byte[] dst = new byte[bodyLength - MessagePacket.HEADER_LENGTH];
				buffer.get(dst);
				p.setBody(dst);
			}
			return p;
		}
	}

	@Override
	public ByteBuffer encode(Packet packet, GroupContext groupContext, ChannelContext channelContext) {
		MessagePacket p = (MessagePacket) packet;
		byte[] body = p.getBody();
		int bodyLen = 0;
		if (body != null) {
			bodyLen = body.length;
		}

		p.setLength(bodyLen + MessagePacket.HEADER_LENGTH);

		ByteBuffer buffer = ByteBuffer.allocate(p.getLength() + MessagePacket.LENGTH_LENGTH);
		buffer.order(ByteOrder.LITTLE_ENDIAN);

		buffer.putInt(p.getLength());
		buffer.putInt(p.getLength());
		buffer.putShort(p.getType());
		buffer.put(p.getEncryptType());
		buffer.put(p.getReserved());

		if (body != null) {
			buffer.put(body);
		}
		return buffer;
	}

	@Override
	public void handler(Packet packet, ChannelContext channelContext) throws Exception {
		MessagePacket p = (MessagePacket) packet;
		byte[] body = p.getBody();
		if (body != null) {
			eventBus.post(new MessageEvent(body, channelContext));
		}
	}

	@Override
	public Packet heartbeatPacket() {
		return MessageMaker.heartbeat();
	}

}
